import subprocess

KERNEL_TREE = "/usr/src/linux"

def find_and_parse_define(name):
    # Some syscalls do not use the SYSCALL_DEFINE macro for some reason...
    # To circumvent the tracing or so?
    if name == "modify_ldt":
        return ["int", "void *", "unsigned long"]
    elif name == 'arch_prctl':
        return ['int', 'unsigned long']
    elif name == 'ioperm':
        return ['unsigned long', 'unsigned long', 'int']
    # Removed since 2.6
    elif name in ('create_module', 'get_kernel_syms', 'query_module'):
        return []
    # Not implemented at all
    elif name in ('nfsservctl', 'getpmsg', 'putpmsg', 'afs_syscall', 'tuxcall',
            'security', 'epoll_ctl_old', 'epoll_wait_old', 'vserver'):
        return []
    # Use different name in SYSCALL_DEFINE...
    elif name == "_sysctl":
        name = "sysctl"
    elif name == "umount2":
        name = "umount"

    try:
        d = subprocess.check_output(['grep', '-A5', '-r', '-h',
            '^SYSCALL_DEFINE[0-9](%s[,)]' % name, '%s/arch/x86' % KERNEL_TREE])
    except subprocess.CalledProcessError:
        d = subprocess.check_output(['grep', '-A5', '-r', '-h',
            '^SYSCALL_DEFINE[0-9](%s[,)]' % name, '%s' % KERNEL_TREE])

    if b"SYSCALL_DEFINE" not in d:
        print("Could not find SYSCALL_DEFINE for %s!" % name)
        exit()

    d = d.replace(b",\n", b", ").replace(b"\t", b" ").replace(b"(\n", b"(")
    while b"  " in d:
        d = d.replace(b"  ", b" ")

    d = d.split(b"\n")[0]
    d = d.split(b"(", 1)[1].replace(b");", b"")
    d = d.split(b",")[1::2]

    d = [t.strip().decode('utf-8') for t in d]

    return d

with open("syscall_nrs.tmp") as f:
    nrs = f.read()

nrs = nrs.replace("#define __NR_", "")
nrs = dict((l.strip().split(" ") for l in nrs.split("\n") if l.strip()))
nrs = sorted(nrs, key=lambda x: int(nrs.get(x)))

with open("syscall_signatures.h", "w") as f:
    f.write("/* Automatically generated by generate_syscall_info.py */\n")
    f.write("/* DO NOT MODIFY */\n\n")
    f.write("#ifndef SYSCALL_SIGNATURES_H\n")
    f.write("#define SYSCALL_SIGNATURES_H\n\n")
    f.write("struct syscall_signature {\n")
    f.write("   unsigned nr;\n")
    f.write("   unsigned nr_args;\n")
    f.write("   const char *name;\n")
    f.write("};\n\n")
    f.write("static struct syscall_signature syscall_signatures[] = {\n")

    for nr, name in enumerate(nrs):
        args = find_and_parse_define(name)
        f.write(' [%d] = { %d, %d, "%s" },\n' %
                (nr, nr, len(args), name))

    f.write("};\n")
    f.write("#endif\n")
